package cn.edu.jxust.core.domain.repository.impl;

import cn.edu.jxust.common.domain.entity.Account;
import cn.edu.jxust.common.domain.entity.Device;
import cn.edu.jxust.common.domain.entity.Site;
import cn.edu.jxust.common.domain.entity.SiteAirType;
import cn.edu.jxust.common.domain.dto.DeviceSiteVo;
import cn.edu.jxust.common.domain.dto.SiteAirTypeVo;
import cn.edu.jxust.common.domain.valobj.SiteAirTypeVoSimple;
import cn.edu.jxust.common.domain.dto.SiteVo;
import cn.edu.jxust.core.infrastructure.mapper.AreaMapper;
import cn.edu.jxust.core.infrastructure.mapper.DeviceMapper;
import cn.edu.jxust.core.infrastructure.mapper.EnterpriseMapper;
import cn.edu.jxust.core.infrastructure.mapper.SiteAirTypeMapper;
import cn.edu.jxust.core.infrastructure.mapper.SiteMapper;
import cn.edu.jxust.common.response.Result;
import cn.edu.jxust.common.response.ResultUtils;
import cn.edu.jxust.common.response.enums.ResultStatus;
import cn.edu.jxust.core.domain.repository.AirtypeService;
import cn.edu.jxust.core.domain.repository.SiteAirTypeService;
import cn.edu.jxust.core.domain.repository.SiteService;
import cn.edu.jxust.core.infrastructure.util.Const;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author QiuKangming
 * @since 2020-07-06
 */
@Service
@SuppressWarnings("unused")
public class SiteServiceImpl extends ServiceImpl<SiteMapper, Site> implements SiteService {

    @Resource
    private SiteMapper siteMapper;
    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private SiteAirTypeMapper siteAirTypeMapper;
    @Resource
    private SiteAirTypeService siteAirTypeService;
    @Resource
    private AirtypeService airtypeService;
    @Resource
    private AreaMapper areaMapper;
    @Resource
    private EnterpriseMapper enterpriseMapper;

    /**
     * 添加监测点信息
     * @param siteVo 监测点视图对象
     * @return boolean
     */
    @Override
    public boolean addSite(SiteVo siteVo) {

        Site site = new Site();
        BeanUtil.copyProperties(siteVo, site);
        return siteMapper.insert(site) == 1;

    }

    /**
     * 修改监测点信息
     * @param siteVo 监测点视图对象
     * @return boolean
     */
    @Override
    public Result modifySiteInfo(SiteVo siteVo) {

        Site site = siteMapper.selectById(siteVo.getId());
        //判断监测点是否绑定
        if(siteIsBinding(siteVo.getId())){//绑定了
            if(!site.getAreaId().equals(siteVo.getAreaId()) || !site.getEnterpriseId().equals(siteVo.getEnterpriseId())){
                //修改了区域或者企业
                return ResultUtils.resultWithoutData(ResultStatus.FAILED, "修改失败, 该监测点已绑定设备, 请先解绑");
            }
        }
        BeanUtil.copyProperties(siteVo, site);
        return siteMapper.updateById(site) == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "更新监测点信息成功")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "更新该监测点信息失败, 请重试");

    }

    /**
     * 根据 id 获取监测点信息
     * @param id 监测点id
     * @return Site
     */
    @Override
    public Site getSiteById(Integer id) {

        return siteMapper.selectById(id);

    }


    /**
     * 查询监测点信息, 超级管理员 和 区级管理员: 可以获取所有监测点信息, 可以根据区域id, 企业id, 地址模糊查询监测点信息
     *              区级管理员: 只能查看自己所在区域的监测点信息
     *              企业用户: 只能查看自己所在企业的监测点信息
     * @param paramMap 请求参数
     * @param page 页数
     * @param size 一页几条数据
     * @return IPage<Site>
     */
    @Override
    @Transactional(readOnly = true)
    public IPage<SiteVo> getSitePage(Map<String, String[]> paramMap, Integer page, Integer size) {

        //获取当前用户
        Account account = (Account) SecurityUtils.getSubject().getPrincipal();
        //是否是区管理员
        boolean isDadmin = account.getRoleId().equals(Const.DISTRICT_ADMIN_ID);
        //是否是企业用户
        boolean isEnter = account.getRoleId().equals(Const.ENTERPRISE_USER_ID);

        //需要过滤掉不必要的参数[防止恶意篡改 url 地址中的参数]
        String[] params = {"area_id", "enterprise_id", "is_binding", "site_detail_address"};
        //封装查询条件
        QueryWrapper<Site> wrapper = new QueryWrapper<>();

        paramMap.forEach((k,v)->{
            for (String param : params) {

                if(param.equals(k) && !v[0].equals("")){

                    //区级管理员需要绕过 area_id, 因为 area_id 是固定值
                    if(isDadmin){
                        //如果是区级管理员
                        if(k.equals("area_id")){
                            wrapper.eq(k, account.getAreaId());
                            continue;
                        }
                    //企业用户需要绕过 area_id, enterprise_id, 因为 area_id enterprise_id 都是固定值
                    }else if(isEnter){
                        //如果是企业用户
                        if(k.equals("area_id")){
                            wrapper.eq(k, account.getAreaId());
                            continue;
                        }else if(k.equals("enterprise_id")){
                            wrapper.eq(k, account.getEnterpriseId());
                            continue;
                        }
                    }
                    wrapper.eq(k, v[0]);

                }
            }
        });

        //如果是区管理员, 但是没带该参数
        if(isDadmin){
            wrapper.eq("area_id", account.getAreaId());
        }
        //如果是企业用户, 都没带参数
        if(isEnter){
            wrapper.eq("area_id", account.getAreaId());
            wrapper.eq("enterprise_id", account.getEnterpriseId());
        }
        IPage<Site> pageInfo1 = siteMapper.selectPage(new Page<>(page, size), wrapper);
        List<Site> list = pageInfo1.getRecords();
        List<SiteVo> siteVos = this.toSiteVo(list);
        IPage<SiteVo> pageInfo = new Page<>();

        pageInfo.setTotal(pageInfo1.getTotal());
        pageInfo.setSize(pageInfo1.getSize());
        pageInfo.setPages(pageInfo1.getPages());
        pageInfo.setCurrent(pageInfo1.getCurrent());
        pageInfo.setRecords(siteVos);

        return pageInfo;

    }

    /**
     * 获取未绑定设备的监测点列表
     * @param page 第几页
     * @param size 一页几条数据
     * @return IPage<Site>
     */
    @Override
    public IPage<Site> getNoBindingSite(Integer page, Integer size) {

        return siteMapper.selectPage(new Page<>(page, size), new QueryWrapper<Site>().eq("is_binding", Const.NOT_BINDING));

    }

    /**
     * 根据id判断监测点是否绑定监测设备
     * @param id 监测点id
     * @return boolean
     */
    @Override
    public boolean siteIsBinding(Integer id) {

        return getById(id).getIsBinding().equals(Const.BINDING);

    }

    /**
     * 监测点 绑定/解绑 设备
     * @param deviceSiteVo 设备视图对象
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindingDevice(DeviceSiteVo deviceSiteVo) {

        //解绑需要把设备的监测点id号置为 NOT_BINDING
        int val = deviceSiteVo.getIsBinding().equals(Const.BINDING) ? Const.BINDING : Const.NOT_BINDING;
        Device device = Device.builder().id(deviceSiteVo.getDeviceId()).deviceSiteId(val == Const.BINDING ? deviceSiteVo.getSiteId() : Const.NOT_BINDING).isBinding(val).build();
        int b = deviceMapper.updateById(device);
        Site site = Site.builder().id(deviceSiteVo.getSiteId()).isBinding(val).build();
        int s = siteMapper.updateById(site);
        return (b + s) == 2;

    }

    /**
     * 根据监测点id获取监测气体列表
     * @param page 第几页
     * @param size 一页几条数据
     * @param siteId 监测点id
     * @return IPage<SiteAirTypeVo>
     */
    @Override
    @Transactional(readOnly = true)
    public IPage<SiteAirTypeVo> getSiteAirTypeVoListBySiteId(Integer page, Integer size, Integer siteId) {

        QueryWrapper<SiteAirType> wrapper = null;
        if(null != siteId){
            wrapper = new QueryWrapper<>();
            wrapper.eq("site_id", siteId);
        }

        IPage<SiteAirType> pageInfo1 = siteAirTypeMapper.selectPage(new Page<>(page, size), wrapper);
        IPage<SiteAirTypeVo> pageInfo = new Page<>();
        List<SiteAirTypeVo> siteAirTypeVoList = this.toSiteAirTypeVo(pageInfo1.getRecords());

        pageInfo.setRecords(siteAirTypeVoList);
        pageInfo.setCurrent(pageInfo1.getCurrent());
        pageInfo.setPages(pageInfo1.getPages());
        pageInfo.setSize(pageInfo1.getSize());
        pageInfo.setTotal(pageInfo1.getTotal());

        return pageInfo;

    }

    /**
     * 监测点删除或添加监测气体
     * @param siteAirTypeVo 监测点监测气体视图对象
     * @return Result
     */
    @Override
    public Result addOrdelSiteAirType(SiteAirTypeVo siteAirTypeVo) {

        // id 字符串
        String airTypeIds = siteAirTypeVo.getAirTypeIds();

        if(!StringUtils.isEmpty(airTypeIds)){
            String[] _airTypeIds = airTypeIds.split(",");
            if(_airTypeIds.length > 0){
                List<Integer> airTypeIdList = new ArrayList<>();
                for (String airTypeId : _airTypeIds) {
                    if(!StringUtils.isEmpty(airTypeId)){
                        airTypeIdList.add(Integer.parseInt(airTypeId));
                    }else {
                        return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请提供合法的气体类型");
                    }

                }
                //有增加监测气体的 ids
                SiteAirType siteAirType = new SiteAirType();
                siteAirType.setSiteId(siteAirTypeVo.getSiteId());
                for (Integer id : airTypeIdList) {
                    //判断是添加还是删除
                    if(siteAirTypeVo.getAddOrdel() == 1){

                        //判断该监测点是否添加了此监测气体, 查询出该监测点监测的气体id列表
                        if(siteAirTypeMapper.getAirIdListBySiteId(siteAirTypeVo.getSiteId()).contains(id)){
                            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请勿重复添加监测气体");
                        }

                        //添加
                        siteAirType.setAirtypeId(id);
                        siteAirType.setEditor(siteAirTypeVo.getEditor());
                        siteAirTypeMapper.insert(siteAirType);
                        return ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "添加监测气体成功");

                    }else if(siteAirTypeVo.getAddOrdel() == 0){

                        //删除
                        Map<String, Object> map = new HashMap<>(2);
                        map.put("site_id", siteAirTypeVo.getSiteId());
                        map.put("airtype_id", id);
                        siteAirTypeMapper.deleteByMap(map);
                        return ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "删除监测气体成功");

                    }
                }
            }else{
                //空串
                return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请提供合法的气体类型");
            }
        }
        return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请勿提交空字符串, 添加失败");

    }

    /**
     * 根据设备id查询监测点的监测气体列表
     * @param deviceId 设备id
     * @return List<SiteAirTypeVo>
     */
    @Override
    public List<SiteAirTypeVoSimple> getSiteAirTypeByDeviceId(Integer deviceId) {

        Integer siteId = deviceMapper.getSiteIdById(deviceId);
        List<SiteAirType> siteAirTypeList = siteAirTypeMapper.selectList(new QueryWrapper<SiteAirType>().eq("site_id", siteId));
        return this.toSiteAirTypeVoSimple(siteAirTypeList);

    }

    /**
     * 根据监测点id删除监测点
     * @param id 监测点id号
     * @return Result
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result delSiteById(Integer id) {

        //获取当前用户
        Account account = (Account) SecurityUtils.getSubject().getPrincipal();
        //判断如果是区管理员或者企业用户
        List<Integer> siteIds = null;
        if(account.getRoleId().equals(Const.DISTRICT_ADMIN_ID)){
            //区级管理员
            siteIds = this.getSiteIdsByAreaId(account.getAreaId());
        }else if(account.getRoleId().equals(Const.ENTERPRISE_USER_ID)){
            //企业用户
            siteIds = this.getSiteIdsByAreaIdAndEnterpriseId(account.getAreaId(), account.getEnterpriseId());
        }
        if(siteIds != null && siteIds.size() != 0 && !siteIds.contains(id)){
            log.warn("尝试删除权限不足/不存在的资源, 越级删除设备");
            return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID);
        }

        //如果当前监测点绑定了设备, 是不能删除的
        if(this.siteIsBinding(id)){
            //true为以绑定
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "当前监测点已经绑定设备,无法删除,请先解绑");
        }

        int i = siteMapper.deleteById(id);
        //检查该监测点是否有监测的气体信息

        //删除监测的气体信息
        int count = siteAirTypeService.getCountBySiteId(id);
        if(count > 0){
            int c = siteAirTypeService.delSiteAirBySiteId(id);
        }

        return i == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "成功删除该监测点")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "删除该监测点信息失败");

    }

    /**
     * 根据区域id查询该区域的监测点id列表
     * @param areaId 区域id
     * @return List<Integer>
     */
    @Override
    public List<Integer> getSiteIdsByAreaId(Integer areaId) {

        return siteMapper.getSiteIdsByAreaId(areaId);

    }

    /**
     * 根据区域id和企业id获取该企业的监测点id列表
     * @param areaId 区域id
     * @param enterpriseId 企业id
     * @return List<Integer>
     */
    @Override
    public List<Integer> getSiteIdsByAreaIdAndEnterpriseId(Integer areaId, Integer enterpriseId) {

        return siteMapper.getSiteIdsByAreaIdAndEnterpriseId(areaId, enterpriseId);

    }

    /**
     * 据 区域id和企业id查询该企业下的监测点个数
     * @param areaId 区域id
     * @param enterpriseId 企业id
     * @return int
     */
    @Override
    public int checkSiteCountByAreaIdAndEnterpriseId(Integer areaId, Integer enterpriseId) {

        return siteMapper.checkSiteCountByAreaIdAndEnterpriseId(areaId, enterpriseId);

    }

    /**
     * 将 List<Site> 转换成 List<SiteVo>
     * @param sites 监测点列表
     * @return List<SiteVo>
     */
    private List<SiteVo> toSiteVo(List<Site> sites){

        //声明变量
        List<SiteVo> siteVos = new ArrayList<>(sites.size());
        //遍历设备列表
        sites.forEach(site -> {
            //1. 首先把相同的字段填充
            SiteVo siteVo = new SiteVo();
            BeanUtil.copyProperties(site, siteVo);
            //2. 填充其他字段: deviceSiteId, deviceIMEI, areaName, enterpriseName
            siteVo.setSiteDeviceId(deviceMapper.getIdBySiteId(siteVo.getId()));
            siteVo.setDeviceIMEI(deviceMapper.getIMEIById(siteVo.getSiteDeviceId()));
            siteVo.setAreaName(areaMapper.getAreaNameById(siteVo.getAreaId()));
            siteVo.setEnterpriseName(enterpriseMapper.getEnterNameById(siteVo.getAreaId(), siteVo.getEnterpriseId()));

            siteVos.add(siteVo);
        });

        return siteVos;

    }

    /**
     * 将 List<SiteAirType> 转换成 List<SiteAirTypeVo>
     * @param siteAirTypeList 监测点监测气体视图对象
     * @return List<SiteAirTypeVo>
     */
    private List<SiteAirTypeVo> toSiteAirTypeVo(List<SiteAirType> siteAirTypeList){

        //声明变量
        List<SiteAirTypeVo> siteAirTypeVoList = new ArrayList<>(siteAirTypeList.size());
        //遍历列表
        siteAirTypeList.forEach(siteAirType -> {

            //1. 首先把相同的字段填充
            SiteAirTypeVo siteAirTypeVo = new SiteAirTypeVo();
            BeanUtil.copyProperties(siteAirType, siteAirTypeVo);
            //2. 填充其他字段: siteDetailAddress airName
            siteAirTypeVo.setSiteDetailAddress(siteMapper.getSiteDetailNameById(siteAirTypeVo.getSiteId()));
            siteAirTypeVo.setAirName(airtypeService.getAirNameById(siteAirTypeVo.getAirtypeId()));

            siteAirTypeVoList.add(siteAirTypeVo);
        });

        return siteAirTypeVoList;

    }

    /**
     * 将List<SiteAirType> 转换成 List<SiteAirTypeVoSimple>
     * @param siteAirTypeList  siteAirTypeList
     * @return List<SiteAirTypeVoSimple>
     */
    private List<SiteAirTypeVoSimple> toSiteAirTypeVoSimple(List<SiteAirType> siteAirTypeList){

        //声明变量
        List<SiteAirTypeVoSimple> list = new ArrayList<>(siteAirTypeList.size());
        //遍历列表
        siteAirTypeList.forEach(siteAirType -> list.add(SiteAirTypeVoSimple.builder()
                .airId(siteAirType.getAirtypeId())
                .airName(airtypeService.getAirNameById(siteAirType.getAirtypeId()))
                .build()));

        return list;

    }

}
